package view.maze;

import java.io.File;
import java.util.Observable;

import org.eclipse.swt.SWT;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.KeyListener;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.FontData;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.FileDialog;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.MessageBox;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;

import view.View;

public class MazeView extends Observable implements View, Runnable
{
	// Data Members
	private Display display;
	private Shell shell;
	private MazeBoard board;
	private Button startReset;
	private Button undo;
	private Button mute;
	private int score;
	private Text scoreText;
	private Text scoreTitle;
	private int userCommand;
	private MazeMenu menu;
	 boolean  ArrowUp=false;
		boolean ArrowDown=false;  
		boolean ArrowLeft=false; 
		boolean ArrowRight=false;

	

	// Statics
	public static final int GAME_OVER = -999;
	public static final int EMPTY = 0;
	public static final int ACTION_ARROW_UP = 0;
	public static final int ACTION_ARROW_DOWN = 1;
	public static final int ACTION_ARROW_LEFT = 2;
	public static final int ACTION_ARROW_RIGHT = 3;
	public static final int ACTION_START_RESET = 4;
	public static final int ACTION_ARROW_UP_LEFT = 77;
	public static final int ACTION_ARROW_UP_RIGHT = 99;
	public static final int ACTION_ARROW_DOWN_RIGHT = 33;
	public static final int ACTION_ARROW_DOWN_LEFT = 11;
	
	
	
	public static final int ACTION_UNDO = 5;
	public static final int ACTION_SAVE = 6;
	public static final int ACTION_LOAD = 7;
	public static final int ACTION_MUTE = 16;

	

	// MazeView EMPTY CTOR
	public MazeView()	{}

	private void initComponents()
	{
		display = new Display();
		shell = new Shell(display);
		shell.setLayout(new GridLayout(2, false));
		shell.setSize(650,550);
		shell.setText("Maze");

		// Create the menuBar
		this.menu = new MazeMenu(this, shell);		

		// Create the Start / Restart button
		startReset = new Button(shell, SWT.PUSH);
		startReset.setText("Start / Restart");
		startReset.setLayoutData(new GridData(SWT.FILL, SWT.TOP, false, false, 1, 1));

		// Create the board
		this.board = new MazeBoard(shell, SWT.FILL);
		board.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 5));

		// Create the Undo button
		undo = new Button(shell, SWT.PUSH);
		undo.setText("Undo");
		undo.setLayoutData(new GridData(SWT.FILL, SWT.TOP, false, false, 1, 1));

		// Create a Separator Label
		Label separatorButtons = new Label(shell, SWT.SEPARATOR | SWT.SHADOW_OUT | SWT.HORIZONTAL);
		separatorButtons.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false, 1, 1));

		// Create the Mute Check box button
		mute = new Button(shell, SWT.CHECK);
		mute.setText("Mute Music");
		mute.setLayoutData(new GridData(SWT.FILL, SWT.TOP, false, false, 1, 1));

		// Create the scoreTitle text
		scoreTitle = new Text(shell,SWT.SINGLE);
		scoreTitle.setText("Score:");
		scoreTitle.setBackground(this.shell.getBackground());
		scoreTitle.setFont(new Font(display, new FontData("Tahoma", shell.getClientArea().height * 5 / 100, SWT.BOLD)));
		scoreTitle.setLayoutData(new GridData(SWT.LEFT, SWT.BOTTOM, false, true, 1, 1));

		// Create the scoreText text
		scoreText = new Text(shell, SWT.SINGLE);
		scoreText.setText(Integer.toString(score));
		scoreText.setBackground(this.shell.getBackground());
		scoreText.setFont(new Font(display, new FontData("Tahoma", shell.getClientArea().height * 5 / 100, SWT.NORMAL)));
		scoreText.setLayoutData(new GridData(SWT.FILL, SWT.BOTTOM, false, false, 1, 1));	

		// Add listeners
		addListeners();
		

		// Set the menu bar to the shell
		shell.setMenuBar(menu.getMenuBar());

		// Set the mouse & keyboard focus to the board
		this.board.setFocus();

		// Open the shell window
		shell.open();
	}

	// Adds the appropriate listeners to the buttons
	private void addListeners() 
	{
		
		
		board.addKeyListener(new KeyListener() {
			
			
			@Override
			public void keyReleased(KeyEvent event) {
			
				if(ArrowLeft && ArrowUp)
				{
				  setUserCommand(ACTION_ARROW_UP_LEFT);
				   
				}
				else if(ArrowLeft && ArrowDown)
				{
					setUserCommand(ACTION_ARROW_DOWN_LEFT);	
				}
				else if(ArrowRight && ArrowUp)
				{
					setUserCommand(ACTION_ARROW_UP_RIGHT);
				}
				else if(ArrowRight && ArrowDown)
				{
					setUserCommand(ACTION_ARROW_DOWN_RIGHT);
				}
				else if(ArrowUp)
				{
					setUserCommand(ACTION_ARROW_UP);
				}
				else if(ArrowDown)
				{
					setUserCommand(ACTION_ARROW_DOWN);
				}
				else if(ArrowLeft)
				{
					setUserCommand(ACTION_ARROW_LEFT);
				}
				else if(ArrowRight)
				{
					setUserCommand(ACTION_ARROW_RIGHT);
				}
				    ArrowUp=false;
					ArrowDown=false;  
					ArrowLeft=false; 
					ArrowRight=false;
				
			}
			
			@Override
			public void keyPressed(KeyEvent event) {
				if(event.keyCode == SWT.ARROW_UP)
				{
					
				ArrowUp=true;
				}
				if(event.keyCode == SWT.ARROW_DOWN)
				{
				ArrowDown=true;
				
				}
				if(event.keyCode == SWT.ARROW_LEFT)
				{
				ArrowLeft=true;
				}
				if(event.keyCode == SWT.ARROW_RIGHT)
				{
				ArrowRight=true;
				}
				
			}
		});
		// If startReset button is clicked, setUserCommand to MazeView.ACTION_START_RESET
		startReset.addSelectionListener(new SelectionListener() {
			@Override
			public void widgetSelected(SelectionEvent e) 
			{
				setUserCommand(MazeView.ACTION_START_RESET);
				board.forceFocus();
				
			}

			@Override
			public void widgetDefaultSelected(SelectionEvent e)
			{ /* DO NOTHING */ }

		});

		undo.addSelectionListener(new SelectionListener() {

			@Override
			public void widgetSelected(SelectionEvent e) 
			{
				setUserCommand(MazeView.ACTION_UNDO);
				board.forceFocus();
			}

			@Override
			public void widgetDefaultSelected(SelectionEvent e) 
			{ /* DO NOTHING */ }
		});
		//Mute
		mute.addSelectionListener(new SelectionListener() {

			@Override
			public void widgetSelected(SelectionEvent e) 
			{
				setUserCommand(MazeView.ACTION_MUTE);
				board.setFocus();
			}

			@Override
			public void widgetDefaultSelected(SelectionEvent e) 
			{  /* DO NOTHING */  }
			
			
		});

	}


	
	

	@Override
	// setBoardData and then redraw the board
	public void displayData(int[][] data, final int score)
	{
		this.board.setBoardData(data);
		this.score = score;

		display.syncExec(new Runnable() {
			@Override
			public void run()
			{
				board.redraw();
				scoreText.setText(Integer.toString(score));				
			}
		});
	}

	@Override
	// Return the userCommand integer
	public int getUserCommand() 
	{
		return userCommand;
	}

	// Update the local command integer
	public void setUserCommand(int cmd)
	{
		// Update the local command variable
		this.userCommand = cmd;

		// Notify Observers
		setChanged();
		notifyObservers();
	}

	@Override
	// Run the initComponents method and loop over the display.readAndDispath method
	public void run() 
	{
		initComponents();

		while (!shell.isDisposed())
		{
			if (!display.readAndDispatch())
			{
				display.sleep();
			}
		}
		display.dispose();
	}

	@Override
	// Sets the score
	public void setScore(int score)
	{
		this.score = score;
	}

	@Override
	// Returns the score
	public int getScore(int score)
	{
		return this.score;
	}

	protected MazeBoard getBoard()
	{
		return this.board;
	}

	@Override
	public String getSaveLocation() 
	{
		boolean canWriteToFile = false;
		File saveFile = null;
		String saveFileLocation = null;

		FileDialog fileDialog = new FileDialog(shell, SWT.SAVE);
		fileDialog.setText("Save Game");
		fileDialog.setFilterExtensions(new String[] {"*.txt"});


		while (!canWriteToFile)
		{
			saveFileLocation = fileDialog.open();

			if (saveFileLocation == null)
				return null;

			saveFile = new File(saveFileLocation);

			if ((saveFile.exists()) && (!saveFile.isDirectory()))
			{
				MessageBox messageBoxOverwrite = new MessageBox(shell, SWT.ICON_QUESTION | SWT.YES | SWT.NO);
				messageBoxOverwrite.setText("File Exists");
				messageBoxOverwrite.setMessage("Would you like to overwrite the file selected?");

				int response = messageBoxOverwrite.open();

				if (response == SWT.YES)
				{
					if (saveFile.canWrite())
						canWriteToFile = true;
					else
					{
						MessageBox messageBoxWritePerm = new MessageBox(shell, SWT.ICON_ERROR | SWT.OK);
						messageBoxWritePerm.setText("Can't Write");
						messageBoxWritePerm.setMessage("The file " + saveFileLocation + " can not be written to. Please check that you have write permissions.");
					}
				}
				else
				{

				}
			}
			else if (saveFile.exists()) // saveFile exists, but is a directory
			{
				MessageBox messageBoxDir = new MessageBox(shell, SWT.ICON_ERROR | SWT.OK);
				messageBoxDir.setText("Directory Chosen");
				messageBoxDir.setMessage("Can't choose a directory.");
			}
			else
			{
				MessageBox messageBoxCreate = new MessageBox(shell, SWT.ICON_QUESTION | SWT.YES | SWT.NO);
				messageBoxCreate.setText("File Does Not Exist");
				messageBoxCreate.setMessage("File does not exist, would you like to create it ?");

				int response = messageBoxCreate.open();

				if (response == SWT.YES)
				{
					canWriteToFile = true;
				}
			}
		}

		if (saveFileLocation.substring(saveFileLocation.length()-4).equals(".txt"))
			return saveFileLocation;
		else
			return saveFileLocation + ".txt";
	}

	@Override
	public String getLoadLocation() 
	{
		boolean canReadFromFile = false;
		File loadFile = null;
		String loadFileLocation = null;

		FileDialog fileDialog = new FileDialog(shell, SWT.OPEN);
		fileDialog.setText("Load Game");
		fileDialog.setFilterExtensions(new String[] {"*.txt"});


		while (!canReadFromFile)
		{
			loadFileLocation = fileDialog.open();

			if (loadFileLocation == null)
				return null;

			loadFile = new File(loadFileLocation);

			if (loadFile.exists() && loadFile.isDirectory()) // saveFile exists, but is a directory
			{
				MessageBox messageBoxDir = new MessageBox(shell, SWT.ICON_ERROR | SWT.OK);
				messageBoxDir.setText("Directory Chosen");
				messageBoxDir.setMessage("Can't choose a directory.");
			}
			else if (!loadFile.exists())
			{
				MessageBox messageBoxCreate = new MessageBox(shell, SWT.ICON_QUESTION | SWT.YES | SWT.NO);
				messageBoxCreate.setText("File does not exist");
				messageBoxCreate.setMessage("File " + loadFileLocation + "does not exist. Please choose a different one.");
			}
			else // loadFile.exists() == true
			{
				if (!loadFile.canRead())
				{
					MessageBox messageBoxRead = new MessageBox(shell, SWT.ICON_ERROR | SWT.OK);
					messageBoxRead.setText("Read Error");
					messageBoxRead.setMessage("File " + loadFileLocation + "can not be read. Please verify that you have read permissions.");
				}
				else
				{
					canReadFromFile = true;
				}
			}
		}

		if (loadFileLocation.substring(loadFileLocation.length()-4).equals(".txt"))
			return loadFileLocation;
		else
			return loadFileLocation + ".txt";
	}

	@Override
	public int[][] getBoardArray() {
		// TODO Auto-generated method stub
		return null;
	}

}